package com.candy.common.controller;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNodeConfig;
import cn.hutool.core.lang.tree.TreeUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.candy.common.constant.RequestPath;
import com.candy.common.entity.PathMessage;
import com.candy.common.exception.BusinessException;
import com.candy.common.result.R;
import com.candy.common.service.ICommonService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.error.ErrorAttributes;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.context.request.ServletWebRequest;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * <p>
 * 通用表单 前端控制器
 * </p>
 *
 * @author pxs
 * @since 2021-12-13
 */
@Slf4j
@RestController
public class CommonController implements ErrorController
{
    @Autowired
    private ICommonService commonService;

    /**
     * 错误信息
     */
    @Autowired
    private ErrorAttributes errorAttributes;

    /**
     * 错误处理路径
     */
    private static final String ERROR_PATH = "/error";

    /**
     * web上下文路径
     */
    @Value("${server.servlet.context-path:}")
    private String contextPath;

    /**
     * 错误路径
     */
    @Override
    public String getErrorPath()
    {
        return ERROR_PATH;
    }

    /**
     * 处理
     */
    @RequestMapping(value = ERROR_PATH)
    @ResponseBody
    public R errorApiHander(HttpServletRequest request, @RequestBody(required = false) Object params)
    {
        ServletWebRequest requestAttributes = new ServletWebRequest(request);
        Map<String, Object> attr = this.errorAttributes.getErrorAttributes(requestAttributes, false);
        String path = (String) attr.get("path");
        Integer status = (Integer) attr.get("status");
        if (status != HttpStatus.NOT_FOUND.value())
        {
            R r = new R();
            r.put(R.CODE_TAG, status);
            return r;
        }
        //未知请求，进去通用处理操作
        log.info(String.format("尝试解析通用请求, %s", path));
        PathMessage pathMessage = getPathMessage(path);
        switch (RequestPath.getRequestPathByPath(pathMessage.getRequestPath()))
        {
            case SAVE:
                return save((HashMap<String, Object>) params, pathMessage.getTableName());
            case SAVE_BATCH:
                return saveBatch((Collection<HashMap<String, Object>>) params, pathMessage.getTableName());
            case EDIT:
                return edit((HashMap<String, Object>) params, pathMessage.getTableName());
            case EDIT_BATCH:
                return editBatch((Collection<HashMap<String, Object>>) params, pathMessage.getTableName());
            case LIST:
                return listPage((HashMap<String, Object>) params, pathMessage.getTableName());
            case TREE:
                return tree((HashMap<String, Object>) params, pathMessage.getTableName());
            case DELETE:
                return delete((HashMap<String, Object>) params, pathMessage.getTableName());
            case DETAIL:
                Long id;
                try
                {
                    id = Long.valueOf(pathMessage.getRequestPath());
                } catch (Exception e)
                {
                    return R.error(String.format("ID获取失败：%s", path));
                }
                if (id > 0)
                {
                    return getInfo(id, pathMessage.getTableName());
                }
            default:
                throw new BusinessException(String.format("未知的请求：%s", path));
        }
    }

    /**
     * 分页查询
     *
     * @param params
     * @param tableName
     * @return com.candy.common.result.R
     */
    public R listPage(HashMap<String, Object> params, String tableName)
    {
        IPage pageModel = commonService.getMapsPage(BaseController.getPage(), params, tableName);
        return R.success(pageModel);
    }

    /**
     * 查询详情
     *
     * @param id
     * @param tableName
     * @return com.candy.common.result.R
     */
    public R getInfo(Long id, String tableName)
    {
        HashMap<String, Object> map = commonService.getMapById(id, tableName);
        if (map != null)
        {
            return R.success(map);
        }
        else
        {
            return R.error("数据不存在");
        }
    }

    /**
     * 保存
     *
     * @param entity
     * @param tableName
     * @return com.candy.common.result.R
     */
    public R save(HashMap<String, Object> entity, String tableName)
    {
        return R.success(commonService.saveMap(entity, tableName));
    }

    /**
     * 批量保存
     *
     * @param entityList
     * @param tableName
     * @return com.candy.common.result.R
     */
    public R saveBatch(Collection<HashMap<String, Object>> entityList, String tableName)
    {
        return R.success(commonService.saveMapBatch(entityList, tableName));
    }

    /**
     * 编辑
     *
     * @param entity
     * @param tableName
     * @return com.candy.common.result.R
     */
    public R edit(HashMap<String, Object> entity, String tableName)
    {
        entity.remove("isDeleted");
        return R.success(commonService.updateMapById(entity, tableName));
    }

    /**
     * 批量编辑
     *
     * @param entityList
     * @param tableName
     * @return com.candy.common.result.R
     */
    public R editBatch(Collection<HashMap<String, Object>> entityList, String tableName)
    {
        for (HashMap<String, Object> entity : entityList)
        {
            entity.remove("isDeleted");
        }
        return R.success(commonService.updateMapBatchById(entityList, tableName));
    }

    /**
     * 逻辑删除
     *
     * @param param
     * @param tableName
     * @return com.candy.common.result.R
     */
    public R delete(HashMap<String, Object> param, String tableName)
    {
        if (param.containsKey("ids"))
        {
            List<Object> idList = (List<Object>) param.get("ids");
            List<HashMap<String, Object>> entityList = new ArrayList<>();
            for (Object id : idList)
            {
                HashMap<String, Object> entity = new HashMap<>(2);
                entity.put("id", id);
                entity.put("isDeleted", 1);
                entityList.add(entity);
            }
            return R.success(commonService.updateMapBatchById(entityList, tableName));
        }
        else if (param.containsKey("id"))
        {
            Long id = Long.valueOf(param.get("id").toString());
            HashMap<String, Object> entity = new HashMap<>(2);
            entity.put("id", id);
            entity.put("isDeleted", 1);
            return R.success(commonService.updateMapById(entity, tableName));
        }
        else
        {
            return R.error("未获取到要删除的数据");
        }
    }

    /**
     * 获取路径信息
     *
     * @return com.candy.common.entity.CommonTableInfo
     */
    private PathMessage getPathMessage(String path)
    {
        if (StringUtils.isEmpty(path))
        {
            throw new RuntimeException("尝试解析通用请求，请求路径获取失败");
        }
        if (!StringUtils.isEmpty(contextPath) && contextPath.equals("/"))
        {
            path = path.substring(contextPath.length());
        }
        if (path.lastIndexOf("/") > 1)
        {
            PathMessage pathMessage = new PathMessage();
            pathMessage.setRequestPath(path.substring(path.lastIndexOf("/") + 1));
            path = path.substring(1, path.lastIndexOf("/"));
            String tableName = path.replace("/", "_");
            pathMessage.setTableName(tableName);
            return pathMessage;
        }
        throw new RuntimeException("尝试解析通用请求，表名称解析失败");
    }


    @ApiOperation(value = "树列表")
    public R tree(HashMap<String, Object> params, String tableName)
    {
        List<HashMap<String,Object>> list = commonService.getMapList(params, tableName);
        //配置
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        // 自定义属性名 都要默认值的
        treeNodeConfig.setWeightKey("orderNum");
        treeNodeConfig.setNameKey("title");
        treeNodeConfig.setIdKey("id");
        treeNodeConfig.setParentIdKey("pid");
        treeNodeConfig.setChildrenKey("children");
        // 最大递归深度
        treeNodeConfig.setDeep(3);
        //转换器
        List<Tree<Long>> treeNodes = TreeUtil.build(list, 0L, treeNodeConfig,
                (treeNode, tree) -> {
                    tree.setId((Long) treeNode.get("id"));
                    tree.setParentId((Long) treeNode.get("pid"));
                    tree.setWeight(Long.valueOf(treeNode.get("orderNum").toString()));
                    tree.setName(String.valueOf(treeNode.get("name")));
                });
        return R.success(treeNodes);
    }
}